package org.slg.oracleproject.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.slg.oracleproject.entity.Role;
import org.slg.oracleproject.entity.User;
import org.slg.oracleproject.entity.UserRole; // 新增：用户-角色中间表实体
import org.slg.oracleproject.entity.dto.LoginDTO;
import org.slg.oracleproject.entity.dto.RefreshTokenDTO;
import org.slg.oracleproject.entity.vo.LoginVO;
import org.slg.oracleproject.exception.BusinessException;
import org.slg.oracleproject.mapper.UserMapper;
import org.slg.oracleproject.respones.CommonResult;
import org.slg.oracleproject.service.RoleService;
import org.slg.oracleproject.service.UserRoleService; // 新增：中间表服务
import org.slg.oracleproject.service.UserService;
import org.slg.oracleproject.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private RoleService roleService;

    @Autowired
    private UserRoleService userRoleService;


    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public LoginVO userLogin(LoginDTO loginDTO) {
        // 1. 查询用户（用户名不存在则直接抛出异常）
        QueryWrapper<User> userQuery = new QueryWrapper<>();
        userQuery.eq("username", loginDTO.getUsername());
        User user = this.getOne(userQuery);
        if (user == null) {
            throw new BusinessException("用户名或密码错误"); // 统一错误提示，避免泄露用户存在性
        }
        // 2. 验证密码（核心：必须添加密码比对，此处假设使用BCryptPasswordEncoder）
        // 注意：实际项目中需注入PasswordEncoder（如@Autowired private PasswordEncoder passwordEncoder;）
        if (!passwordEncoder.matches(loginDTO.getPassword(), user.getPassword())) {
            throw new BusinessException("用户名或密码错误");
        }
        // 3. 验证用户状态（账号是否禁用）
        if (user.getStatus() == 0) {
            throw new BusinessException("账号已禁用，请联系管理员");
        }
        // 4. 查询用户关联的角色ID（用于生成accessToken，JwtTokenUtil需要List<Integer> roles）
        QueryWrapper<UserRole> userRoleQuery = new QueryWrapper<>();
        userRoleQuery.eq("user_id", user.getId());
        List<UserRole> userRoles = userRoleService.list(userRoleQuery);
        if (userRoles.isEmpty()) {
            throw new BusinessException("用户未分配角色，无法登录");
        }
        List<Integer> roleIds = userRoles.stream()
                .map(UserRole::getRoleId) // 提取角色ID（Integer类型，匹配JwtTokenUtil的参数要求）
                .collect(Collectors.toList());
        // 5. 查询角色名称（用于返回给前端显示，非令牌必要信息）
        QueryWrapper<Role> roleQuery = new QueryWrapper<>();
        roleQuery.in("id", roleIds);
        List<Role> roles = roleService.list(roleQuery);
        List<String> roleNames = roles.stream()
                .map(Role::getRoleName)
                .collect(Collectors.toList());
        String accessToken = jwtTokenUtil.generateAccessToken(
                user.getId(),       // 用户ID
                user.getUsername(), // 用户名
                roleNames       // 角色列表（JwtTokenUtil要求List<Integer>）
        );
        String refreshToken = jwtTokenUtil.generateRefreshToken(
                user.getId(),       // 用户ID
                user.getUsername()  // 用户名（刷新令牌无需携带角色）
        );
        // 7. 封装返回结果（包含双令牌和用户基本信息）
        return new LoginVO(
                accessToken,    // 访问令牌
                refreshToken,   // 刷新令牌
                user.getId(),   // 用户ID
                user.getUsername(), // 昵称
                roleNames       // 角色名称列表
        );
    }

    /**
     * token刷新
     *
     * @param refreshTokenDTO
     * @return
     */
    @Override
    public LoginVO refreshToken(RefreshTokenDTO refreshTokenDTO) {
        String refreshToken = refreshTokenDTO.getRefreshToken();
        if (refreshToken == null || refreshToken.isEmpty()) {
            throw new BusinessException("刷新令牌不能为空");
        }

        // 1. 验证refresh token是否有效（签名正确且未过期）
        if (!jwtTokenUtil.validateRefreshToken(refreshToken)) {
            throw new BusinessException("无效的刷新令牌，请重新登录");
        }

        try {
            // 2. 从refresh token中解析用户信息
            Integer userId = jwtTokenUtil.getUserIdFromToken(refreshToken);
            log.info("userId = {}", userId);

            String username = jwtTokenUtil.getUsernameFromToken(refreshToken);
            if (userId == null || username == null) { // 补充空校验，避免后续NPE
                throw new BusinessException("令牌信息不完整");
            }

            // 3. 验证用户是否存在
            User user = this.getById(userId);
            if (user == null) {
                throw new BusinessException("用户不存在");
            }
            // 可选：如果允许用户名修改后继续刷新，可删除下面的校验
            if (!user.getUsername().equals(username)) {
                throw new BusinessException("用户名已修改，请重新登录");
            }

            // 4. 重新获取用户与角色信息（删除冗余的QueryWrapper定义）
            QueryWrapper<UserRole> userRoleQuery = new QueryWrapper<>();
            userRoleQuery.eq("user_id", userId); // 直接用userId，无需通过user.getId()
            List<UserRole> userRoles = userRoleService.list(userRoleQuery);
            // 可选：如果要求用户必须有角色，补充校验
            if (userRoles.isEmpty()) {
                throw new BusinessException("用户未分配角色，无法刷新令牌");
            }
            List<Integer> roles = userRoles.stream()
                    .map(UserRole::getRoleId)
                    .toList();
            log.info("获取到角色id列表roles = {}", roles);

            // 获取用户角色(非必须)
            QueryWrapper<Role> roleQuery = new QueryWrapper<>();
            roleQuery.in("id", roles); // 直接用userId，无需通过user.getId()
            List<String> list = roleService.list(roleQuery).stream().map(Role::getRoleName).toList();
            // 5. 生成新令牌
            String newAccessToken = jwtTokenUtil.generateAccessToken(userId, username, list);
            String newRefreshToken = jwtTokenUtil.generateRefreshToken(userId, username);

            // 6. 封装返回
            LoginVO loginVO = new LoginVO();
            loginVO.setUserId(userId);
            loginVO.setUserName(username);
            loginVO.setAccessToken(newAccessToken);
            loginVO.setRefreshToken(newRefreshToken);
            loginVO.setRoles(list);
            return loginVO;

        } catch (BusinessException e) { // 捕获业务异常，直接抛出
            throw e;
        } catch (Exception e) { // 捕获其他异常（如JWT解析失败）
            log.error("刷新令牌失败", e);
            throw new BusinessException("刷新令牌失败，请重新登录");
        }
    }


    /**
     * 新增或更新用户（存在则更新，不存在则新增）
     */
    public boolean saveOrUpdateUser(User user) {
        if (user.getPassword() != null) {
            user.setPassword(passwordEncoder.encode(user.getPassword()));
        }
        return this.saveOrUpdate(user); // 内部会根据主键是否存在判断新增/更新
    }


}
